/*
 * PhotonRTOS础光实时操作系统 -- tc397串口控制台驱动
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Jiayuan Liang <liangjiayuan@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <photon/init.h>
#include <photon/irq.h>


#include <asm/types.h>

#include <photon/printk.h>
#include <photon/console.h>

#include "IfxAsclin_Asc.h"
#include "IfxCpu_Irq.h"
#include "Ifx_Console.h"
#include "IfxAsclin.h"
#include "Assert.h"
#include <Ifx_Shell.h>
#include <autosar/task.h>
#include <Os_internel.h>

/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/

#define SERIAL_BAUDRATE0         115200
#define SERIAL_PIN_RX0           IfxAsclin0_RXA_P14_1_IN
#define SERIAL_PIN_TX0           IfxAsclin0_TX_P14_0_OUT
#define INTPRIO_ASCLIN0_TX       16      /* Priority of the ISR */
#define INTPRIO_ASCLIN0_RX       15      /* Priority of the ISR */
#define INTPRIO_ASCLIN0_ER       23      /* Priority of the ISR */

#define ASC_TX_BUFFER_SIZE       1024
#define ASC_RX_BUFFER_SIZE       1024


#define SIZE                    13                                      /* Size of the string                       */

uint32_t g_correctTransactions = 0;                       /* Incremented when a correct DMA transaction is finished   */
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
/* Declaration of the ASC handle */
IfxStdIf_DPipe  g_ascStandardInterface;     /* Standard interface object            */

IfxAsclin_Asc g_ascHandle;                       /* Declaration of the ASC handle

/* Declaration of the FIFOs parameters */
static uint8 g_ascTxBuffer[ASC_TX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
static uint8 g_ascRxBuffer[ASC_RX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];

/* Shell commands and help descriptions */
#define COMMAND_INFO                "info"
#define COMMAND_TOGGLE              "toggle"
#define COMMAND_HELP                "help"
#define COMMAND_PS                  "ps"
#define COMMAND_MEM_TEST            "mem_test"
#define COMMAND_LEFT_ON             "1"
#define COMMAND_LEFT_OFF            "2"
#define COMMAND_RIGHT_ON            "3"
#define COMMAND_RIGHT_OFF           "4"

#define COMMAND_TURN_RIGHT_ON           "5"
#define COMMAND_TURN_RIGHT_OFF          "6"
#define COMMAND_TURN_LEFT_ON            "7"
#define COMMAND_TURN_LEFT_OFF           "8"

//#define COMMAND_INFO_HELP_TEXT      "   : Show the example's info"
//#define COMMAND_TOGGLE_HELP_TEXT    " : Command to toggle LEDs, " \
//                              "         The correct syntax for this command is: " \
//                              "         '" COMMAND_TOGGLE " [0/1/2/3/4]'"
#define COMMAND_HELP_HELP_TEXT      		"       : 显示操作信息"
#define COMMAND_PS_HELP_TEXT        		"         : 显示进程信息"
#define COMMAND_MEM_TEST_HELP_TEXT  		"   : 测试内存保护功能"
#define COMMAND_LEFT_OFF_HELP_TEXT  		"          : 熄灭左车灯"
#define COMMAND_LEFT_ON_HELP_TEXT   		"          : 点亮左车灯"
#define COMMAND_RIGHT_ON_HELP_TEXT  		"          : 点亮右车灯"
#define COMMAND_RIGHT_OFF_HELP_TEXT 		"          : 熄灭右车灯"
#define COMMAND_TURN_RIGHT_ON_HELP_TEXT     "          : 点亮右转灯"
#define COMMAND_TURN_RIGHT_OFF_HELP_TEXT    "          : 熄灭右转灯"
#define COMMAND_TURN_LEFT_ON_HELP_TEXT      "          : 点亮左转灯"
#define COMMAND_TURN_LEFT_OFF_HELP_TEXT     "          : 熄灭左转灯"

#define IdWaiter2 2
#define IdWaiter3 3

typedef struct{
	unsigned char left_lamp:1;
	unsigned char left_turn_lamp:1;
	unsigned char left_stop_lamp:1;

	unsigned char right_lamp:1;
	unsigned char right_turn_lamp:1;
	unsigned char right_stop_lamp:1;
}car_led_def;

unsigned char txData[8] = {
		0
};

int car_led_contrl(unsigned char *buff, unsigned char left_lamp, unsigned char left_turn_lamp, unsigned char left_stop_lamp, unsigned char right_lamp, unsigned char right_turn_lamp, unsigned char right_stop_lamp)
{
	if(buff == NULL)
		return -1;

	(*(car_led_def *)&buff[0]).left_lamp = left_lamp;
	(*(car_led_def *)&buff[0]).left_turn_lamp = left_turn_lamp;
	(*(car_led_def *)&buff[0]).left_stop_lamp = left_stop_lamp;

	(*(car_led_def *)&buff[0]).right_lamp = right_lamp;
	(*(car_led_def *)&buff[0]).right_turn_lamp = right_turn_lamp;
	(*(car_led_def *)&buff[0]).right_stop_lamp = right_stop_lamp;
	return 0;
}


Ifx_Shell       g_shellInterface;                                           /* Shell interface object               */

/* The transfer buffers allocate memory for the data itself and for FIFO runtime variables.
 * 8 more bytes have to be added to ensure a proper circular buffer handling independent from
 * the address to which the buffers have been located.
 */
uint8 g_uartTxBuffer[ASC_TX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
uint8 g_uartRxBuffer[ASC_RX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];

boolean printShellInfo(pchar args, void *data, IfxStdIf_DPipe *io);
boolean toggleLEDsShell(pchar args, void *data, IfxStdIf_DPipe *io);

#define IdTestTask15 15

static int if_turn_left_on, if_turn_right_on;

boolean mem_test(void)
{
	ActivateTaskAsyn(IdTestTask15);
	return TRUE;
}

boolean left_on(void)
{
//	int ret = car_led_contrl(txData, 1, 0, 0, 0, 0, 0);//发送can信号到继电器，注释掉，改为板子上的led灯闪烁。下述注释同理。
//	arch_send_can_message(0x101, txData, 8);
	turn_on_led4();
	return TRUE;
}

boolean left_off(void)
{
//	int ret = car_led_contrl(txData, 0, 0, 0, 0, 0, 0);
//	arch_send_can_message(0x101, txData, 8);
	turn_off_led4();
	return TRUE;
}

boolean right_on(void)
{
//	int ret = car_led_contrl(txData, 0, 0, 0, 1, 0, 0);
//	arch_send_can_message(0x101, txData, 8);
	turn_on_led5();
	return TRUE;
}

boolean right_off(void)
{
//	int ret = car_led_contrl(txData, 0, 0 , 0, 0, 0, 0);
//	arch_send_can_message(0x101, txData, 8);
	turn_off_led5();
	return TRUE;
}

static void __turn_left_on(VAR(OsWaiterRefType, AUTOMATIC) waiter)
{
	static uint8_t left_state = 0;
//	if (left_state == 0) {
//		car_led_contrl(txData, 0, 1, 0, 0, 0, 0);
//		arch_send_can_message(0x101, txData, 8);
//		left_state = 1;
//	} else if (left_state == 1) {
//		car_led_contrl(txData, 0, 0 ,0,0,0,0);
//		arch_send_can_message(0x101, txData, 8);
//		left_state = 0;
//	}
	blinkLED4();
}

boolean turn_left_on(void)
{
	uint32_t counter_value;
	if (if_turn_left_on == 1) {
		printk("左转向灯已经打开。\n");
		return TRUE;
	}
	if_turn_left_on = 1;
	GetCounterValue(0, &counter_value);
	DeclareWaiter(IdWaiter2, counter_value + 36, 36, 0, &__turn_left_on, NULL_PTR);

	return TRUE;
}

boolean turn_left_off(void)
{
	if (if_turn_left_on == 0) {
		printk("左转向灯已经关闭。\n");
		return TRUE;
	}
	remove_waiter_from_counter(&autosar_waiters[IdWaiter2], 0);
//	car_led_contrl(txData, 0, 0 ,0,0,0,0);
//	arch_send_can_message(0x101, txData, 8);
	turn_off_led4();
	if_turn_left_on = 0;
	return TRUE;
}

static void __turn_right_on(VAR(OsWaiterRefType, AUTOMATIC) waiter)
{
	static uint8_t right_state = 0;
//	if (right_state == 0) {
//		car_led_contrl(txData, 0, 0, 0, 0, 1, 0);
//		arch_send_can_message(0x101, txData, 8);
//		right_state = 1;
//	} else if (right_state == 1) {
//		car_led_contrl(txData, 0, 0 ,0,0,0,0);
//		arch_send_can_message(0x101, txData, 8);
//		right_state = 0;
//	}
	blinkLED5();
}

boolean turn_right_on(void)
{
	uint32_t counter_value;
	if (if_turn_right_on == 1) {
		printk("右转向灯已经打开。\n");
		return TRUE;
	}
	if_turn_right_on = 1;
	GetCounterValue(0, &counter_value);
	DeclareWaiter(IdWaiter3, counter_value + 36, 36, 0, &__turn_right_on, NULL_PTR);

	return TRUE;
}

boolean turn_right_off(void)
{
	if (if_turn_right_on == 0) {
		printk("右转向灯已经关闭。\n");
		return TRUE;
	}
	remove_waiter_from_counter(&autosar_waiters[IdWaiter3], 0);
//	car_led_contrl(txData, 0, 0 ,0,0,0,0);
//	arch_send_can_message(0x101, txData, 8);
	turn_off_led5();
	if_turn_right_on = 0;
	return TRUE;
}

/* Array that stores the supported Shell commands */
const Ifx_Shell_Command g_shellCommands[] = {
//    {COMMAND_INFO,   COMMAND_INFO_HELP_TEXT,    &g_shellInterface, &printShellInfo     },
//    {COMMAND_TOGGLE, COMMAND_TOGGLE_HELP_TEXT,  &g_shellInterface, &toggleLEDsShell    },
    {COMMAND_HELP,   COMMAND_HELP_HELP_TEXT,    &g_shellInterface, &Ifx_Shell_showHelp },
	{COMMAND_PS,     COMMAND_PS_HELP_TEXT,      &g_shellInterface, &ShowAllTaskInfo},
	{COMMAND_MEM_TEST, COMMAND_MEM_TEST_HELP_TEXT, &g_shellInterface, &mem_test},
	{COMMAND_LEFT_ON, COMMAND_LEFT_ON_HELP_TEXT, &g_shellInterface, &left_on},
	{COMMAND_LEFT_OFF, COMMAND_LEFT_OFF_HELP_TEXT, &g_shellInterface, &left_off},
	{COMMAND_RIGHT_ON, COMMAND_RIGHT_ON_HELP_TEXT, &g_shellInterface, &right_on},
	{COMMAND_RIGHT_OFF, COMMAND_RIGHT_OFF_HELP_TEXT, &g_shellInterface, &right_off},
	{COMMAND_TURN_RIGHT_ON, COMMAND_TURN_RIGHT_ON_HELP_TEXT, &g_shellInterface, &turn_right_on},
	{COMMAND_TURN_RIGHT_OFF, COMMAND_TURN_RIGHT_OFF_HELP_TEXT, &g_shellInterface, &turn_right_off},
	{COMMAND_TURN_LEFT_ON, COMMAND_TURN_LEFT_ON_HELP_TEXT, &g_shellInterface, &turn_left_on},
	{COMMAND_TURN_LEFT_OFF, COMMAND_TURN_LEFT_OFF_HELP_TEXT, &g_shellInterface, &turn_left_off},
    IFX_SHELL_COMMAND_LIST_END
};


/* Function to show information about the example through the shell */
boolean printShellInfo(pchar args, void *data, IfxStdIf_DPipe *io)
{
    return TRUE;
}

boolean toggleLEDsShell(pchar args, void *data, IfxStdIf_DPipe *io)
{
	return TRUE;
}

/*********************************************************************************************************************/
/*---------------------------------------------Function Implementations----------------------------------------------*/
/*********************************************************************************************************************/
/* Adding of the interrupt service routines */
IFX_INTERRUPT(asclin0TxISR, 2, INTPRIO_ASCLIN0_TX);  /* Adding the Interrupt Service Routine */
void asclin0TxISR(void)
{
	IfxAsclin_Asc_isrTransmit(&g_ascHandle);
}

IFX_INTERRUPT(asc0RxISR, 2, INTPRIO_ASCLIN0_RX);
void asc0RxISR(void)
{
	IfxStdIf_DPipe_onReceive(&g_ascStandardInterface);
}

IFX_INTERRUPT(asc0RxISR, 2, INTPRIO_ASCLIN0_ER);
void asc0ErrISR(void)
{
	IfxStdIf_DPipe_onError(&g_ascStandardInterface);
}

/* This function initializes the ASCLIN UART module */
static void init_ASCLIN_UART(void)
{
	/* Initialize an instance of IfxAsclin_Asc_Config with default values */
	  IfxAsclin_Asc_Config ascConfig;

	  IfxAsclin_Asc_initModuleConfig(&ascConfig, SERIAL_PIN_TX0.module);
	  /* Set the desired baud rate */
	  ascConfig.baudrate.baudrate = SERIAL_BAUDRATE0;
	  ascConfig.baudrate.oversampling = IfxAsclin_OversamplingFactor_16; /* Set the oversampling factor */
	  /* Configure the sampling mode */
	  ascConfig.bitTiming.medianFilter = IfxAsclin_SamplesPerBit_three;             /* Set the number of samples per bit*/
	  ascConfig.bitTiming.samplePointPosition = IfxAsclin_SamplePointPosition_8;    /* Set the first sample position    */
	  /* ISR priorities and interrupt target */
	  ascConfig.interrupt.txPriority = INTPRIO_ASCLIN0_TX;
	  ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN0_RX;
	  ascConfig.interrupt.erPriority = INTPRIO_ASCLIN0_ER;
	  ascConfig.interrupt.typeOfService = IfxCpu_Irq_getTos(2);
	  /* FIFO configuration */
	  ascConfig.txBuffer = &g_ascTxBuffer;
	  ascConfig.txBufferSize = ASC_TX_BUFFER_SIZE;
	  ascConfig.rxBuffer = &g_ascRxBuffer;
	  ascConfig.rxBufferSize = ASC_RX_BUFFER_SIZE;
	  /* Port pins configuration */
	  const IfxAsclin_Asc_Pins pins =
	  {
		  NULL_PTR,         IfxPort_InputMode_pullUp,      /* CTS pin not used    */
		  &SERIAL_PIN_RX0,   IfxPort_InputMode_pullUp,     /* RX pin              */
		  NULL_PTR,         IfxPort_OutputMode_pushPull,   /* RTS pin not used    */
		  &SERIAL_PIN_TX0,   IfxPort_OutputMode_pushPull,  /* TX pin              */
		  IfxPort_PadDriver_cmosAutomotiveSpeed1
	  };
	  ascConfig.pins = &pins;
	  /* Initialize module with above parameters  */
	  IfxAsclin_Asc_initModule(&g_ascHandle, &ascConfig);

	  IfxAsclin_Asc_stdIfDPipeInit(&g_ascStandardInterface, &g_ascHandle);

	  Ifx_Console_init(&g_ascStandardInterface);
}

void init_shell(void)
{
	Ifx_Shell_Config shellConf;

	Ifx_Shell_initConfig(&shellConf);                       /* Initialize the structure with default values         */

	shellConf.standardIo = &g_ascStandardInterface;         /* Set a pointer to the standard interface              */
	shellConf.commandList[0] = &g_shellCommands[0];         /* Set the supported command list                       */

	Ifx_Shell_init(&g_shellInterface, &shellConf);          /* Initialize the Shell with the given configuration    */
}


static void tc397_simple_write(const char *s, unsigned count)
{
	IfxAsclin_Asc *asc = (IfxAsclin_Asc *)&g_ascHandle;
	IfxAsclin_Asc_write(asc, s, &count, TIME_INFINITE);
}

static uint8_t 	* earlycon_base = NULL;
static int32_t  tc397_init_simple()
{
	init_ASCLIN_UART();
	init_shell();

	return 0;
}

void runShellInterface(void)
{
    /* Process the received data */

    Ifx_Shell_process(&g_shellInterface);
}

void test_write(const char *s, unsigned count)
{
	IfxAsclin_Asc *asc = (IfxAsclin_Asc *)&g_ascHandle;
	IfxAsclin_Asc_write(asc, s, &count, TIME_INFINITE);
}

const struct simple_console global_simple_console = {
	.name  = "tc397uart0",
	.init = tc397_init_simple,
	.write = tc397_simple_write,
};

